#include "empty_function.h"

//全局变量
TestingDatas g_testing_datas_host   = TESTING_DATAS__INIT;
TestingDatas g_testing_datas_remote = TESTING_DATAS__INIT;
Heart g_heart                       = HEART__INIT;
ControlCommand g_control_command    = CONTROL_COMMAND__INIT;
FileCommand g_file_command          = FILE_COMMAND__INIT;
CommandResult g_command_result      = COMMAND_RESULT__INIT;

G_Lst_Var g_lst_var;

//所有统计信息链表
LIST_HEAD(list_tested_ids); //被测设备ID集合，每个ID 8字节
LIST_HEAD(list_aux_ids);    //背景设备ID集合，每个ID 8字节

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//通讯消息主结构
static void pack_into_data_header(DataHeader__MsgType msg_type, uint8_t *datas, int len, uint8_t **mqtt_send_buf, int *mqtt_send_len)
{
    DataHeader data_header = DATA_HEADER__INIT;

    data_header.id.data     = (uint8_t *)g_lst_var.dev_id;
    data_header.id.len      = DEV_ID_LEN;
    data_header.msg_type    = msg_type;
    data_header.upload_time = get_now_time();
    data_header.datas.data  = datas;
    data_header.datas.len   = len;

    //打包
    *mqtt_send_len = data_header__get_packed_size(&data_header);
    *mqtt_send_buf = malloc(*mqtt_send_len);
    if(*mqtt_send_buf == NULL)
    {
        return;
    }

    data_header__pack(&data_header, *mqtt_send_buf);
}

//打包实时数据
void pack_testing_datas(TestingDatas *testingdatas, TestingDatas__DevType type, uint8_t **mqtt_send_buf, int *mqtt_send_len)
{
    if(type == TESTING_DATAS_RECV_DEV)
    {
        /*
        **
        *注：以下查找方案效率较低（存在多次重复查找），只是阐明过滤规，需厂家自行优化
        **
        */

        //如果是接收数据，在没有指定被测设备时，只上传自身数据
        if(list_empty(&list_tested_ids))
        {
            return;
        }

        //如果本身既不是被测车也不是背景车
        if(find_id_from_ids(g_lst_var.dev_id, &list_tested_ids) != 1 &&
           find_id_from_ids(g_lst_var.dev_id, &list_aux_ids) != 1)
        {
            return;
        }

        //背景车收到了背景车、其他车数据不上传，若收到被测车需上传
        if(find_id_from_ids(g_lst_var.dev_id, &list_aux_ids) == 1)
        {
            if(find_id_from_ids((char *)testingdatas->dev_id.data, &list_tested_ids) != 1)
            {
                return;
            }
        }

        //被测车收到了其他车数据不上传，若收到被测车、背景车需上传
        if(find_id_from_ids(g_lst_var.dev_id, &list_tested_ids) == 1)
        {
            if(find_id_from_ids((char *)testingdatas->dev_id.data, &list_tested_ids) != 1 &&
               find_id_from_ids((char *)testingdatas->dev_id.data, &list_aux_ids) != 1)
            {
                return;
            }
        }
    }

    uint8_t *buf = NULL;
    int len      = 0;

    testingdatas->data_type = type;

    //打包
    len = testing_datas__get_packed_size(testingdatas);
    buf = malloc(len);
    if(buf == NULL)
    {
        return;
    }

    testing_datas__pack(testingdatas, buf);

    //打包主结构
    pack_into_data_header(DATA_HEADER__MSG_TYPE__TESTINGDATAS, buf, len, mqtt_send_buf, mqtt_send_len);

    //内存释放
    if(buf)
    {
        free(buf);
        buf = NULL;
    }

    return;
}

//发送心跳数据
static void *thread_send_heart_data(void *arg)
{
    uint8_t *buf = NULL;
    int len      = 0;

    uint8_t *mqtt_send_buf = NULL; //MQTT上传的数据指针
    int mqtt_send_len      = 0;    //MQTT上传的数据长度

    while(1)
    {
        //版本号
        g_heart.version = get_app_version();

        //TODO 上报状态和拥塞状态通过control_command获取

        //设备类型
        g_heart.dev_type = get_dev_type();

        //打包
        len = heart__get_packed_size(&g_heart);
        buf = malloc(len);
        if(buf == NULL)
        {
            return NULL;
        }
        heart__pack(&g_heart, buf);

        //打包主结构
        pack_into_data_header(DATA_HEADER__MSG_TYPE__HEART, buf, len, &mqtt_send_buf, &mqtt_send_len);

        //发送到MQTT
        if(mqtt_send_buf)
        {
            mqtt_upload_datas(mqtt_send_buf, mqtt_send_len, TOPIC_UPLOAD_DATAS);
        }

        //内存释放
        if(buf)
        {
            free(buf);
            buf = NULL;
        }

        if(mqtt_send_buf)
        {
            free(mqtt_send_buf);
            mqtt_send_buf = NULL;
        }

        sleep(5);
    }
    return NULL;
}

//命令回复
static void command_response(DataHeader__MsgType msg_type, char *command_id, int result)
{
    g_command_result.command_id = command_id;
    g_command_result.result     = result;

    uint8_t *buf           = NULL;
    int len                = 0;
    uint8_t *mqtt_send_buf = NULL; //MQTT上传的数据指针
    int mqtt_send_len;             //MQTT上传的数据长度

    //打包
    len = command_result__get_packed_size(&g_command_result);
    buf = malloc(len);
    if(buf == NULL)
    {
        return;
    }
    command_result__pack(&g_command_result, buf);

    //打包主结构
    pack_into_data_header(msg_type, buf, len, &mqtt_send_buf, &mqtt_send_len);

    //发送到MQTT
    if(mqtt_send_buf)
    {
        mqtt_upload_datas(mqtt_send_buf, mqtt_send_len, TOPIC_COMMAND_RET);
    }
    printf("resp:%s,%d\n", g_command_result.command_id, g_command_result.result);

    //内存释放
    if(buf)
    {
        free(buf);
        buf = NULL;
    }

    if(mqtt_send_buf)
    {
        free(mqtt_send_buf);
        mqtt_send_buf = NULL;
    }
}

//将设备ID添加到链表中
static void deal_contcommd_ids(ControlCommand *controlcommand)
{
    if(controlcommand == NULL)
    {
        return;
    }

    int i = 0;
    for(i = 0; i < controlcommand->n_tested_ids; i++)
    {
        if(controlcommand->tested_ids != NULL)
        {
            if(controlcommand->tested_ids[i]->dev_id.data != NULL)
            {
                insert_into_ids((char *)controlcommand->tested_ids[i]->dev_id.data, &list_tested_ids);
            }
        }
    }

    for(i = 0; i < controlcommand->n_aux_ids; i++)
    {
        if(controlcommand->aux_ids != NULL)
        {
            if(controlcommand->aux_ids[i]->dev_id.data != NULL)
            {
                insert_into_ids((char *)controlcommand->aux_ids[i]->dev_id.data, &list_aux_ids);
            }
        }
    }
}

//处理自定义命令
static void deal_user_defined_control(ControlCommand *controlcommand)
{
    //todo
    if(controlcommand->command_msg)
    {
        printf("user defined cmd:%s\n", controlcommand->command_msg);
    }
}

//处理控制命令
static void deal_control_command(uint8_t *data, int len)
{
    if(data == NULL)
    {
        return;
    }

    ControlCommand *tmp_controlcommand = control_command__unpack(NULL, len, data);
    if(tmp_controlcommand != NULL)
    {
        switch(tmp_controlcommand->control_type)
        {
            case CONTROL_COMMAND__CONTROL_TYPE__SENDON:
                g_heart.send_state = true;
                deal_contcommd_ids(tmp_controlcommand);
                break;
            case CONTROL_COMMAND__CONTROL_TYPE__SENDOFF:
                g_heart.send_state = false;
                clear_dev_ids(&list_tested_ids);
                clear_dev_ids(&list_aux_ids);
                break;
            case CONTROL_COMMAND__CONTROL_TYPE__REBOOT:
                /* code */
                break;
            case CONTROL_COMMAND__CONTROL_TYPE__CONTROL:
                deal_user_defined_control(tmp_controlcommand);
                break;
            case CONTROL_COMMAND__CONTROL_TYPE__CONGESTIONON:
                g_heart.congestion_enable_state = true;
                break;
            case CONTROL_COMMAND__CONTROL_TYPE__CONGESTIONOFF:
                g_heart.congestion_enable_state = false;
                break;

            default:
                break;
        }

        printf("command_id:%s,s_state:%d,c_state:%d\n", tmp_controlcommand->command_id, g_heart.send_state, g_heart.congestion_enable_state);
    }
    else
    {
        printf("parsing control command faild!\n");
        return;
    }

    //todo
    if(g_heart.send_state == true)
    {
        log_close();
        log_open();
    }
    else
    {
        log_close();
    }

    //命令回复
    command_response(DATA_HEADER__MSG_TYPE__CONTROLCOMMAND, tmp_controlcommand->command_id, 1);

    //内存释放
    control_command__free_unpacked(tmp_controlcommand, NULL);
}

//处理文件命令
static void deal_file_command(uint8_t *data, int len)
{
    if(data == NULL)
    {
        return;
    }

    FileCommand *tmp_filecommand = file_command__unpack(NULL, len, data);
    if(tmp_filecommand != NULL)
    {
        if(tmp_filecommand->command_id != NULL)
            printf("comm_id:%s\n", tmp_filecommand->command_id);
        printf("file_type:%d\n", tmp_filecommand->file_type);
        if(tmp_filecommand->sftp_url != NULL)
            printf("sftp_url:%s\n", tmp_filecommand->sftp_url);
        if(tmp_filecommand->sftp_port)
            printf("sftp_port:%d\n", tmp_filecommand->sftp_port);
        if(tmp_filecommand->sftp_username != NULL)
            printf("username:%s\n", tmp_filecommand->sftp_username);
        if(tmp_filecommand->sftp_password != NULL)
            printf("password:%s\n", tmp_filecommand->sftp_password);
        if(tmp_filecommand->sftp_path != NULL)
            printf("sftp_path:%s\n", tmp_filecommand->sftp_path);
        if(tmp_filecommand->dev_path != NULL)
            printf("dev_path:%s\n", tmp_filecommand->dev_path);
    }
    else
    {
        printf("parsing file command faild!\n");
        return;
    }

    //todo sftp处理
    char cmd[512]      = {0};
    char cmd_resp[512] = {0};
    int ret            = 0;
    if(tmp_filecommand->file_type == FILE_COMMAND__FILE_TYPE__DOWNLOAD)
    {
        snprintf(cmd, sizeof(cmd), "%s %s %d %s %s %s %s 1 | grep Fetching", FILE_COMMAND_SFTP_SHELL, tmp_filecommand->sftp_url, tmp_filecommand->sftp_port,
                 tmp_filecommand->sftp_username, tmp_filecommand->sftp_password, tmp_filecommand->sftp_path, tmp_filecommand->dev_path);
    }
    else
    {
        snprintf(cmd, sizeof(cmd), "%s %s %d %s %s %s %s 2 | grep Uploading", FILE_COMMAND_SFTP_SHELL, tmp_filecommand->sftp_url, tmp_filecommand->sftp_port,
                 tmp_filecommand->sftp_username, tmp_filecommand->sftp_password, tmp_filecommand->sftp_path, tmp_filecommand->dev_path);
    }

    ret = shell_cmd(cmd, cmd_resp, sizeof(cmd_resp));
    if(ret > 0) //成功
    {
        ret = 1;
    }
    else //失败
    {
        ret = 0;
    }

    //命令回复
    command_response(DATA_HEADER__MSG_TYPE__FILECOMMAND, tmp_filecommand->command_id, ret);

    //内存释放
    file_command__free_unpacked(tmp_filecommand, NULL);
}

//接收数据处理，包括控制命令和文件命令
void deal_recv_command(uint8_t *data, int len)
{
    if(data == NULL)
    {
        return;
    }
    //解析数据
    DataHeader *tmp_dataheader = data_header__unpack(NULL, len, data);
    if(tmp_dataheader != NULL)
    {
        if(strncmp((char *)tmp_dataheader->id.data, g_lst_var.dev_id, DEV_ID_LEN) == 0)
        {
            switch(tmp_dataheader->msg_type)
            {
                case DATA_HEADER__MSG_TYPE__CONTROLCOMMAND:
                    if(tmp_dataheader->datas.data)
                    {
                        deal_control_command(tmp_dataheader->datas.data, tmp_dataheader->datas.len);
                    }
                    break;

                case DATA_HEADER__MSG_TYPE__FILECOMMAND:
                    if(tmp_dataheader->datas.data)
                    {
                        deal_file_command(tmp_dataheader->datas.data, tmp_dataheader->datas.len);
                    }
                    break;

                default:
                    break;
            }
        }
        data_header__free_unpacked(tmp_dataheader, NULL);
    }
}

//获取host的TestingDatas
static void get_host_testing_datas()
{
    g_testing_datas_host.data_type          = TESTING_DATAS_SEND_DEV;
    g_testing_datas_host.dev_id.data        = get_host_dev_id();
    g_testing_datas_host.dev_id.len         = DEV_ID_LEN;
    g_testing_datas_host.sign_verify_time   = get_sign_time();
    g_testing_datas_host.sign_verify_result = get_v2x_sign_result();
    g_testing_datas_host.aid                = get_send_msg_aid();
    g_testing_datas_host.cbr                = get_host_cbr();
    g_testing_datas_host.msgcnt             = get_send_msgcount();
    g_testing_datas_host.secmark            = get_send_msg_secmark();
    g_testing_datas_host.speed              = get_send_msg_speed();
    g_testing_datas_host.longitude          = get_send_msg_longitude();
    g_testing_datas_host.latitude           = get_send_msg_latitude();
    g_testing_datas_host.heading            = get_send_msg_heading();
    g_testing_datas_host.dsmp_payload.data  = get_send_msg_dsmppayload();
    g_testing_datas_host.dsmp_payload.len   = get_send_msg_dsmppayload_len();

    //获取向模组发送前的时间
    g_testing_datas_host.send_receive_time = get_now_time();
}

//保存实时数据日志
inline static void save_testingdatas_to_log(uint8_t *mqtt_send_buf, int mqtt_send_len)
{
    //数据记录到日志
    pthread_mutex_lock(&mutex);

    int file_len           = 0;
    uint8_t file_buf[4096] = {0};

    //对protobuf序列化后的数据进行base64编码
    file_len = base64_encode(mqtt_send_buf, mqtt_send_len, file_buf);

    //日志存储
    log_write(file_buf, file_len);

    pthread_mutex_unlock(&mutex);
}

//数据上传到MQTT
inline static void send_testingdatas_to_mqtt(TestingDatas *testingdatas, TestingDatas__DevType type, uint8_t **mqtt_send_buf, int *mqtt_send_len)
{
    ////打包实时数据
    pack_testing_datas(testingdatas, type, mqtt_send_buf, mqtt_send_len);

    //发送到MQTT
    if(*mqtt_send_buf != NULL)
    {
        mqtt_upload_datas(*mqtt_send_buf, *mqtt_send_len, TOPIC_UPLOAD_DATAS);
    }
}

//V2X发送数据处理
static void *thread_v2x_send_data(void *arg)
{
    uint8_t *mqtt_send_buf = NULL; //MQTT上传的数据指针
    int mqtt_send_len;             //MQTT上传的数据长度

    //1.TODO 封装BSM、MAP、SPAT等PC5消息

    //2.封装 host TestingDatas数据
    if(g_heart.send_state)
    {
        get_host_testing_datas();
    }

    //3.将消息发送到模组
    v2x_send_data();

    //4.数据上传到MQTT并进行日志存储
    if(g_heart.send_state)
    {
        //发送实时数据到MQTT
        send_testingdatas_to_mqtt(&g_testing_datas_host, TESTING_DATAS_SEND_DEV, &mqtt_send_buf, &mqtt_send_len);

        //保存日志
        save_testingdatas_to_log(mqtt_send_buf, mqtt_send_len);
    }

    //5.释放内存
    if(mqtt_send_buf)
    {
        free(mqtt_send_buf);
        mqtt_send_buf = NULL;
    }

    return NULL;
}

//获取remote的TestingDatas
static void get_remote_testing_datas()
{
    //pc5数据接收时间
    g_testing_datas_remote.send_receive_time  = get_now_time();
    g_testing_datas_remote.data_type          = TESTING_DATAS_RECV_DEV;
    g_testing_datas_remote.dev_id.data        = get_remote_dev_id();
    g_testing_datas_remote.dev_id.len         = DEV_ID_LEN;
    g_testing_datas_remote.sign_verify_time   = get_verify_time();
    g_testing_datas_remote.sign_verify_result = get_v2x_verify_result();
    g_testing_datas_remote.aid                = get_recv_msg_aid();
    g_testing_datas_remote.cbr                = 101; //接收到的PC5数据上传时，CBR无效
    g_testing_datas_remote.msgcnt             = get_recv_msgcount();
    g_testing_datas_remote.secmark            = get_recv_msg_secmark();
    g_testing_datas_remote.speed              = get_recv_msg_speed();
    g_testing_datas_remote.longitude          = get_recv_msg_longitude();
    g_testing_datas_remote.latitude           = get_recv_msg_latitude();
    g_testing_datas_remote.heading            = get_recv_msg_heading();
    g_testing_datas_remote.dsmp_payload.data  = get_recv_msg_dsmppayload();
    g_testing_datas_remote.dsmp_payload.len   = get_recv_msg_dsmppayload_len();
}

//V2X接收数据处理
static void *thread_v2x_recv_data(void *arg)
{
    uint8_t *mqtt_send_buf = NULL; //MQTT上传的数据指针
    int mqtt_send_len;             //MQTT上传的数据长度

    //1.从模组接收到PC5数据
    v2x_recv_data();

    //2. TODO 解码BSM、MAP、SPAT等PC5消息

    //3.数据上传到MQTT并进行日志存储
    if(g_heart.send_state)
    {
        //3.1封装 remote TestingDatas数据
        get_remote_testing_datas();

        //3.2发送实时数据到MQTT
        send_testingdatas_to_mqtt(&g_testing_datas_remote, TESTING_DATAS_RECV_DEV, &mqtt_send_buf, &mqtt_send_len);

        //3.3保存日志
        save_testingdatas_to_log(mqtt_send_buf, mqtt_send_len);
    }

    //4.释放内存
    if(mqtt_send_buf)
    {
        free(mqtt_send_buf);
        mqtt_send_buf = NULL;
    }

    return NULL;
}

//服务初始化
int lst_service_init()
{
    int iret = -1;

    //mqtt服务初始化
    iret = mqtt_service_init();
    if(iret != 0)
    {
        return iret;
    }

    pthread_t tid;
    pthread_create(&tid, NULL, thread_send_heart_data, NULL);
    pthread_detach(tid);

    return 0;
}

int main(int argc, char const *argv[])
{
    //以下仅作参考，厂家需根据自身框架及逻辑放到适合的位置

    //1.初始化mqtt相关服务
    if(lst_service_init() != 0)
    {
        return -1;
    }

    //2.V2X服务初始化
    v2x_service_init();

    //3.TODO 创建V2X发送和接收处理线程，厂家根据各自框架进行调整
    pthread_t tid_v2x_send;
    pthread_t tid_v2x_recv;
    pthread_create(&tid_v2x_send, NULL, thread_v2x_send_data, NULL);
    pthread_detach(tid_v2x_send);
    pthread_create(&tid_v2x_recv, NULL, thread_v2x_recv_data, NULL);
    pthread_detach(tid_v2x_recv);

    return 0;
}
